package com.lt.flashcard.view;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.GlobalCommand;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.util.Clients;

import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.ActionResult;
import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.entity.Medal;
import com.lt.flashcard.model.entity.MedalHistory;
import com.lt.flashcard.model.entity.Notification;
import com.lt.flashcard.model.entity.User;
import com.lt.flashcard.model.service.EcommerceService;
import com.lt.flashcard.model.service.LearningService;
import com.lt.flashcard.model.service.NotificationService;
import com.lt.flashcard.model.service.Repository;
import com.lt.flashcard.model.service.UserService;

public class QuickNotificationCtrl {

    private List<Notification> notifications = null;
    private int haserror = 0; // the process has error or not
    private List<FlashcardSet> fcs; // the new flashcardset
    private int blueCoin = 0;
    private int yellowCoin = 0;
    private Medal newmedal = null;
    private MedalHistory history = null;
    private int numnew = 0; // number of new message

    @Init
    public void init() {
        getNewNotifications();
    }

    public List<Notification> getNotifications() {
        return notifications;
    }

    public void setNotifications(List<Notification> notifications) {
        this.notifications = notifications;
    }

    @NotifyChange("notifications")
    @Command
    // TODO optimize this, when to update, when no need
    public void getNewNotifications() {
        User user = Utility.getUser();
        NotificationService srv = Repository.getInstance().getNotificationService();
        notifications = srv.getQuickNotificationOfUser(user);

        if (user == null) {
            return;
        }

        // update read status
        List<ObjectId> nn = new ArrayList<ObjectId>();
        String nmid = ""; // new medal id
        for (Notification n : notifications) {
            if (n.getStatus() == Notification.STATUS_UNREAD) {
                if (n.getType() == Notification.TYPE_GETMEDAL) {
                    if (Utility.isEmptyString(nmid)) {
                        nmid = n.getRelatedidstr();
                        nn.add(n.getId());
                    }
                } else {
                    nn.add(n.getId());
                }
            }
        }

        if (nn.size() > 0) {
            srv.updateReadNotifications(nn);
            if (nmid.length() > 0) {
                LearningService lsrv = Repository.getInstance().getLearningService();
                newmedal = lsrv.getMedal(nmid);
                history = lsrv.getMedalhistory(user.getId(), newmedal);
                BindUtils.postNotifyChange(null, null, this, "newmedal");
                BindUtils.postNotifyChange(null, null, this, "history");
            }
        }

        if (numnew != nn.size()) {
            numnew = nn.size();
            BindUtils.postNotifyChange(null, null, this, "numnew");
        }

        int bc = user.getBlueCoin();
        if (bc != blueCoin) {
            blueCoin = bc;
            BindUtils.postNotifyChange(null, null, this, "blueCoin");
        }
        int yc = user.getYellowCoin();
        if (yc != yellowCoin) {
            yellowCoin = yc;
            BindUtils.postNotifyChange(null, null, this, "yellowCoin");
        }
    }

    @NotifyChange({ "newmedal", "history" })
    @Command
    public void closenewmedal() {
        newmedal = null;
        history = null;
    }

    /**
     * Get the name of template to render the notification
     * @param type
     * @return
     */
    public String getTemplateName(int type) {
        switch (type) {
        case Notification.TYPE_SYSTEM:
            return "system";
        case Notification.TYPE_COMMENT:
            return "comment";
        case Notification.TYPE_FRIENDREQUEST:
            return "friendrequest";
        case Notification.TYPE_PRIVATEMSG:
            return "privatemsg";
        case Notification.TYPE_RATING:
            return "rating";
        case Notification.TYPE_SHARE:
            return "share";
        case Notification.TYPE_REPLYCOMMENT:
            return "replycomment";
        case Notification.TYPE_ACCEPTEDFRIENDREQUEST:
            return "acceptfriendrequest";
        case Notification.TYPE_GETMEDAL:
            return "getmedal";
        }
        return "unknow";
    }

    @NotifyChange("notifications")
    @Command
    public void addfriend(@BindingParam("source") Long source, @BindingParam("target") Long target, @BindingParam("msgid") String msgid) {
        UserService usrv = Repository.getInstance().getUserService();
        usrv.addFriendShip(source, target);

        for (Notification not : notifications) {
            if (not.getId().toString().equals(msgid)) {
                not.setType(Notification.TYPE_ACCEPTEDFRIENDREQUEST);
                not.setStatus(Notification.STATUS_READ);
                return;
            }
        }
    }

    @NotifyChange("haserror")
    @Command
    public void addcode(@BindingParam("code") String productcode) {
        if (StringUtils.isBlank(productcode)) {
            return;
        }

        EcommerceService esrv = Repository.getInstance().getEcommerceService();
        ActionResult rs = esrv.userAddCode(Utility.getUser(), productcode);
        if (rs.isError()) {
            haserror = 1;
        } else {
            haserror = 0;
            List<Object> rt = rs.getObjects();
            fcs = new ArrayList<FlashcardSet>();
            if (rt != null) {
                for (Object obj : rt) {
                    fcs.add((FlashcardSet) obj);
                }
            }
            BindUtils.postNotifyChange(null, null, this, "fcs");
            if (fcs.size() == 0) {// product code active coin
                // do update coin
                getNewNotifications();
                // close dialog
                Clients.evalJavaScript("$.fancybox.close()");
            } else {
                // do update created list
                BindUtils.postGlobalCommand(null, null, "updateCreatedList", null);// global command in DashboardCreatedList.java
                // do update coin
                getNewNotifications();
            }
        }
    }

    @NotifyChange({ "haserror", "fcs" })
    @Command
    public void clearcode() {
        haserror = 0;
        fcs = null;
    }

    @NotifyChange("blueCoin")
    @GlobalCommand
    public void updateBlueCoin(@BindingParam("coin") int coin) {
        blueCoin += coin;
    }

    public List<FlashcardSet> getFcs() {
        return fcs;
    }

    public void setFcs(List<FlashcardSet> fcs) {
        this.fcs = fcs;
    }

    public int getHaserror() {
        return haserror;
    }

    public void setHaserror(int haserror) {
        this.haserror = haserror;
    }

    public int getBlueCoin() {
        return blueCoin;
    }

    public void setBlueCoin(int blueCoin) {
        this.blueCoin = blueCoin;
    }

    public int getYellowCoin() {
        return yellowCoin;
    }

    public void setYellowCoin(int yellowCoin) {
        this.yellowCoin = yellowCoin;
    }

    public Medal getNewmedal() {
        return newmedal;
    }

    public void setNewmedal(Medal newmedal) {
        this.newmedal = newmedal;
    }

    public MedalHistory getHistory() {
        return history;
    }

    public void setHistory(MedalHistory history) {
        this.history = history;
    }

    public int getNumnew() {
        return numnew;
    }

    public void setNumnew(int numnew) {
        this.numnew = numnew;
    }
}
